package com.heima.comment.service.impl;

import com.heima.comment.service.CommentHotService;
import com.heima.comment.service.CommentService;
import com.heima.feigns.UserFeign;
import com.heima.model.comment.dtos.CommentDto;
import com.heima.model.comment.dtos.CommentLikeDto;
import com.heima.model.comment.dtos.CommentSaveDto;
import com.heima.model.comment.pojos.ApComment;
import com.heima.model.comment.pojos.ApCommentLike;
import com.heima.model.comment.vos.ApCommentVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.pojos.ApUser;
import com.heima.model.utils.threadlocal.AppThreadLocalUtils;
import org.redisson.api.RLock;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class CommentServiceImpl implements CommentService {

    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private UserFeign userFeign;
    @Autowired
    CommentHotService commentHotService;
    @Resource(name="likesLock")
    RLock rLock;

    @Override
    public ResponseResult saveComment(CommentSaveDto dto) {
        //参数检查hibernate-validator实现
        //检查是否登录
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //评论安全审核,暂不添加,采用阿里云
        //todo
        //保存评论
        ResponseResult<ApUser> userResponseResult = userFeign.findUserById(user.getId());
        //检查登录信息
        if (userResponseResult.getCode() != 0 || userResponseResult.getData() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN, "当前登录信息有误");
        }

        user = userResponseResult.getData();
        ApComment apComment = new ApComment();
        apComment.setAuthorId(user.getId());
        apComment.setAuthorName(user.getName());
        apComment.setImage(user.getImage());
        apComment.setContent(dto.getContent());
        apComment.setEntryId(dto.getArticleId());
        apComment.setCreatedTime(new Date());
        apComment.setUpdatedTime(new Date());
        apComment.setLikes(0);
        apComment.setReply(0);
        apComment.setType((short) 0);
        apComment.setFlag((short) 0);
        mongoTemplate.save(apComment);
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult like(CommentLikeDto dto) {
        //参数检查hibernate-validator实现
        //用户登录
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        //查询评论
        ApComment apComment = mongoTemplate.findById(dto.getCommentId(), ApComment.class);
        if (apComment == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }

        //获取点赞/取消点赞行为
        ApCommentLike commentLike = mongoTemplate.findOne(Query.query(Criteria.where("authorId").is(user.getId())
                .and("commentId").is(dto.getCommentId())), ApCommentLike.class);

        Short operation = dto.getOperation();
        //行为存在且为点赞
        if (commentLike != null && operation.intValue() == 0) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_EXIST, "已点赞");
        }

        rLock.lock();
        try {
            if (operation.intValue() == 0) {
                //行为为点赞
                apComment.setLikes(apComment.getLikes() + 1);//点赞数+1
                mongoTemplate.save(apComment);//更新

                //计算热点评论评论
                if (apComment.getLikes() >= 5 && apComment.getFlag() == 0) {
                    commentHotService.hotCommentExecutor(apComment);
                }

                //保存点赞信息
                commentLike = new ApCommentLike();
                commentLike.setAuthorId(user.getId());
                commentLike.setCommentId(apComment.getId());
                commentLike.setOperation(dto.getOperation());
                mongoTemplate.save(commentLike);
            } else {//行为为取消点赞

                apComment.setLikes(apComment.getLikes() <= 0 ? 0 : apComment.getLikes() - 1);
                mongoTemplate.save(apComment);

                //删除点赞评论信息
                mongoTemplate.remove(Query.query(Criteria.
                        where("authorId").is(user.getId())
                        .and("commentId").is(apComment.getId())), ApCommentLike.class);
            }
        }finally {
            rLock.unlock();
        }
        //装载数据
        Map<String, Object> map = new HashMap();
        map.put("likes", apComment.getLikes());
        return ResponseResult.okResult(map);
    }

    @Override
    public ResponseResult findByArticleId(CommentDto dto) {
        //参数检查hibernate-validator实现
        //检查参数
        if (dto == null || dto.getArticleId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        List<ApComment> apCommentList = loadApCommentList(dto);

        //用户未登录或评论为空,直接返回查询结果
        ApUser user = AppThreadLocalUtils.getUser();
        if (apCommentList == null || apCommentList.size() == 0 || user == null) {
            return ResponseResult.okResult(apCommentList);
        }
        //用户登录,需要加载用户自己的点赞信息
        //从集合中获取所有评论的id
        List<String> commentIdList = apCommentList.stream()
                .map(ApComment::getId)
                .collect(Collectors.toList());
        //根据评论id和用户自己id查询点赞信息
        List<ApCommentLike> apCommentLikeList = mongoTemplate.find(Query.query(Criteria
                        .where("commentId").in(commentIdList)
                        .and("authorId").is(user.getId()))
                , ApCommentLike.class);
        //判断参数
        //如果点赞信息不存在直接返回
        if (apCommentLikeList == null || apCommentLikeList.size() == 0) {
            return ResponseResult.okResult(apCommentList);
        }
        List<ApCommentVo> apCommentVoList = new ArrayList<>();
        apCommentList.forEach(comment -> {
            ApCommentVo apCommentVo = new ApCommentVo();//评论vo,含点赞信息
            BeanUtils.copyProperties(comment, apCommentVo);
            apCommentLikeList.forEach(commentLike -> {
                // 文章评论列表id 和 当前用户点赞评论列表id是否相等
                if (comment.getId().equals(commentLike.getCommentId())) {
                    apCommentVo.setOperation((short) 0);
                }
            });
            apCommentVoList.add(apCommentVo);
        });
        //返回含点赞信息评论集合
        return ResponseResult.okResult(apCommentVoList);
    }

    /**
     * 对热点评论和普通评论进行装载
     * @param dto
     * @return
     */
    private List<ApComment> loadApCommentList(CommentDto dto){
        int size = 10;
        if (dto.getIndex() == 1) {
            return mongoTemplate.find(Query.query(Criteria
                    .where("entryId").is(dto.getArticleId())
                    .and("flag").is(0).and("createdTime")
                    .lt(dto.getMinDate()))
                    .limit(size)
                    .with(Sort.by(Sort.Direction.DESC, "createdTime")),
                    ApComment.class);
        }
        List<ApComment> apCommentList = null;
        //查询热点文章评论
        Query queryHot = Query.query(Criteria
                .where("entryId").is(dto.getArticleId())
                .and("flag").is(1))
                .with(Sort.by(Sort.Direction.DESC, "likes"));
        apCommentList = mongoTemplate.find(queryHot, ApComment.class);
        //有热评且为评论首页时
        if (apCommentList != null){
            size = size - apCommentList.size();
        }
        //查询普通文章评论
        Query queryNormal = Query.query(Criteria
                .where("entryId").is(dto.getArticleId())
                .and("flag").is(0).and("createdTime")
                .lt(dto.getMinDate()))
                .limit(size)
                .with(Sort.by(Sort.Direction.DESC, "createdTime"));
        List<ApComment> normalCommentList = mongoTemplate.find(queryNormal, ApComment.class);

        if (size == 10){
            apCommentList = mongoTemplate.find(queryNormal, ApComment.class);;
        }else {
            apCommentList.addAll(normalCommentList);
        }
        return apCommentList;
    }
}
